﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IronLua.Metadata
{
    public static class BitMasks
    {

        public static int OpCodePosition = 0;
        public static int OpCodeSize = 6;
        public static int RegisterAPosition = OpCodePosition + OpCodeSize;
        public static int RegisterASize = 8;       
        public static int RegisterCPosition = RegisterAPosition + RegisterASize;
        public static int RegisterCSize = 9;
        public static int RegisterBPosition = RegisterCPosition + RegisterCSize;
        public static int RegisterBSize = 9;
        public static int RegisterBxPosition = RegisterCPosition;
        public static int RegisterBxSize = RegisterCSize + RegisterBSize;
        public static int RegisterAxPosition = BitMasks.RegisterAPosition;
        public static int RegisterAxSize = RegisterCSize + RegisterBSize + RegisterASize;

        public static int MaxAxValue = (1 << RegisterAxSize) - 1;
        public static int MaxBxValue = (1 << RegisterBxSize) - 1;
        public static int MaxSbxValue = MaxBxValue >> 1;
        public static int BitRk = (1 << (RegisterBSize - 1));

        public static int MaskFill(int count, int pos)
        {
            var ret = ((~((~0) << count)) << pos);
            return ret;
        }

        public static int MaskEmpty(int count, int pos)
        {
            var ret = ~(MaskFill(count, pos));
            return ret;
        }

        public static OpCodes GetOpCode(uint instr)
        {
            var bitmask = (instr >> OpCodePosition) & MaskFill(OpCodeSize, 0);
            return (OpCodes)(bitmask);
        }

        public static uint GetRegisterA(uint instr)
        {
            return (uint)((instr >> RegisterAPosition) & MaskFill(RegisterASize, 0));
        }

        public static uint GetRegisterB(uint instr)
        {
            return (uint)((instr >> RegisterBPosition) & MaskFill(RegisterBSize, 0));
        }

        public static uint GetRegisterC(uint instr)
        {
            return (uint)((instr >> RegisterCPosition) & MaskFill(RegisterCSize, 0));
        }

        public static uint GetRegisterAx(uint instr)
        {
            return (uint)((instr >> RegisterAxPosition) & MaskFill(RegisterAxSize, 0));
        }

        public static uint GetRegisterBx(uint instr)
        {
            return (uint)((instr >> RegisterBxPosition) & MaskFill(RegisterBxSize, 0));
        }

        public static int GetRegisterSbx(uint instr)
        {
            return (int)GetRegisterBx(instr) - MaxSbxValue;
        }

        public static bool IsBK(uint instr)
        {
            var b = BitMasks.GetRegisterB(instr);
            return (b & BitMasks.BitRk) != 0;
        }

        public static bool IsCK(uint instr)
        {
            var c = BitMasks.GetRegisterC(instr);
            return (c & BitMasks.BitRk) != 0;
        }

        public static uint GetBKIndex(uint instr)
        {
            var b = BitMasks.GetRegisterB(instr);
            return (uint)(b & ~BitMasks.BitRk);
        }

        public static uint GetCKIndex(uint instr)
        {
            var c = BitMasks.GetRegisterC(instr);
            return (uint)(c & ~BitMasks.BitRk);
        }
    }
}
